package lib.gt.map;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.MapView.LayoutParams;

public class OverlayManager {
	
	private static final String TAG = "OverlayManager";
	
	/**
	 * PopupView的模式，SingleMode表示每次只顯示一個PopupView, MultiMode表示可同時顯示多個PopupView，並且點擊空白地方不會將其他PopupView隱藏.<br/>
	 * 默認為SingleMode.
	 * @author tim
	 *
	 */
	public static enum PopupMode {
		SingleMode, MultiMode
	}
	
	private Context mContext;
	private MapView mMapView;
	private PopupMode mMode;
	private int mOverlayDefaultDrawableRes;
	private MapItemizedOverlay mItemizedOverlay;
	private List<AbsPopupView> mPopupViews;		
	private Class<? extends AbsPopupView> mPopupViewClass;
	private List<? extends IOverlayData> mOverlayDatas;
	private int mOverlayDefaultDrawableWidth;
	private int mOverlayDefaultDrawableHeight;
	private Map<Object, int[]> mOverlayDrawableSize = new HashMap<Object, int[]>();
	private IOverlayData mCurrentOverlayDataForSingleMode;
	
	private static OverlayManager instance = null;
	private static boolean sHasInit = false;
	
	protected OverlayManager(MapView mapView, PopupMode mode, int overlayDefaultDrawableRes) {
		mMapView = mapView;
		mMode = mode;
		mOverlayDefaultDrawableRes = overlayDefaultDrawableRes;
		mPopupViews = new ArrayList<AbsPopupView>();
		if(mMapView != null) {
			mContext = mMapView.getContext();
			Drawable d = mContext.getResources().getDrawable(mOverlayDefaultDrawableRes);
			if(d != null) {
				mOverlayDefaultDrawableWidth = d.getIntrinsicWidth();
				mOverlayDefaultDrawableHeight = d.getIntrinsicHeight();
			}
			mItemizedOverlay = new MapItemizedOverlay(d);
		}
	}
	
	public synchronized static void init(MapView mapView) {
		if(instance == null) {
			instance = new OverlayManager(mapView, PopupMode.SingleMode, 0);
			sHasInit = true;
		}
	}
	
	public synchronized static void init(MapView mapView, PopupMode mode) {
		if(instance == null) {
			instance = new OverlayManager(mapView, mode, 0);
			sHasInit = true;
		}
	}
	
	public synchronized static void init(MapView mapView, PopupMode mode, int overlayDefaultDrawableRes) {
		if(instance == null) {
			instance = new OverlayManager(mapView, mode, overlayDefaultDrawableRes);
			sHasInit = true;
		}
	}
	
	public static OverlayManager getInstance() {
		if(instance == null) {
			throw new NullPointerException("Please invoke init(mapView, mode) method before getInstance()!");
		}
		return instance;
	}
	
	public void setPopupViewClass(Class<? extends AbsPopupView> popupViewClass) {
		mPopupViewClass = popupViewClass;
		initPopupViews();
	}
	
	public void setOverlayDatas(List<? extends IOverlayData> datas) {
		mOverlayDatas = datas;
		initOverlays();
		initPopupViews();
	}
	
	private final void initOverlays() {
		if(mOverlayDatas != null) {
			mMapView.getOverlays().remove(mItemizedOverlay);
			mItemizedOverlay.clear();
			mMapView.getOverlays().add(mItemizedOverlay);
			final int dataSize = mOverlayDatas.size();
			for(int i = 0; i < dataSize; i++) {
				final IOverlayData overlayData = mOverlayDatas.get(i);
				MapOverlayItem overlayItem = new MapOverlayItem(overlayData);
				if(mOverlayDefaultDrawableRes <= 0 && overlayData.getOverlayDrawableRes() > 0) {
					Drawable d = mContext.getResources().getDrawable(overlayData.getOverlayDrawableRes());
					final int[] size = new int[2];
					size[0] = d.getIntrinsicWidth();
					size[1] = d.getIntrinsicHeight();
					mOverlayDrawableSize.put(overlayData, size);
					d = mItemizedOverlay.boundDrawableCenter(d);
					overlayItem.setMarker(d);
				}
				mItemizedOverlay.addOverlayItem(overlayItem);
			}
		}
	}
	
	private final void initPopupViews() {
		if(mPopupViews.size() == 0) {	//僅初始化一次
			if(mPopupViewClass != null && mOverlayDatas != null && mOverlayDatas.size() > 0) {
				//TODO 實例化PopupViews
				if(mMode == PopupMode.SingleMode) {
					addPopupView(mOverlayDatas.get(0));
				}
				else {
					final int dataSize = mOverlayDatas.size();
					for(int i = 0; i < dataSize; i++) {
						addPopupView(mOverlayDatas.get(i));
					}
				}
			}
		}
	}
	
	private final void addPopupView(IOverlayData data) {
		AbsPopupView popupView = newPopupView();
		popupView.setVisibility(View.GONE);
		mPopupViews.add(popupView);
		
		mMapView.addView(popupView, new MapView.LayoutParams(popupView.getPopupViewWidth(), 
				popupView.getPopupViewHeight(), null,
				MapView.LayoutParams.BOTTOM_CENTER));
	}
	
	private final AbsPopupView newPopupView() {
		AbsPopupView popupView = null;
		try {
			popupView = mPopupViewClass.getDeclaredConstructor(Context.class).newInstance(mContext);
		} catch(Exception e) {
			e.printStackTrace();
		}
		return popupView;
	}
	
	public MapItemizedOverlay getItemizedOverlay() {
		return mItemizedOverlay;
	}
	
	public void showPopupView(int index) {
		if(mOverlayDatas != null && index >= 0 && index < mOverlayDatas.size()) {
			showPopupView(mOverlayDatas.get(index));
		}
	}
	
	public void showPopupView(IOverlayData data) {
		final int popupViewSize = mPopupViews.size();
		if(mMode == PopupMode.SingleMode) {
			if(popupViewSize > 0) {
				mCurrentOverlayDataForSingleMode = data;
				showPopupView(mPopupViews.get(0), data);
			}
		}
		else {
			if(mOverlayDatas != null) {
				final int overlaySize = mOverlayDatas.size();
				for(int i = 0; i < overlaySize; i++) {
					if(data.equals(mOverlayDatas.get(i))) {
						//找到要Show的PopupView了.
						if(i < popupViewSize) {
							AbsPopupView popupView = mPopupViews.get(i);
							showPopupView(popupView, data);
						}
						break;
					}
				}
			}
		}
	}
	
	/**
	 * SingleMode模式調用此方法無效
	 */
	public void showAllPopupViews() {
		final int popupViewSize = mPopupViews.size();
		if(popupViewSize <= 0) {
			return ;
		}
		if(mMode == PopupMode.SingleMode) {
			//Do nothing.
		}
		else {
			final int dataSize = mOverlayDatas.size();
			for(int i = 0; i < dataSize; i++) {
				showPopupView(i);
			}
		}
	}
	
	private void showPopupView(AbsPopupView popupView, IOverlayData data) {
		popupView.setData(data);
		MapView.LayoutParams lp = (LayoutParams) popupView.getLayoutParams();
		lp.point = new GeoPoint(data.getLatitudeE6(), data.getLongitudeE6());
		final int flowPosition = popupView.getFlowPosition();
		int offsetX = 0, offsetY = 0;
		int[] overlayDrawableSize = mOverlayDrawableSize.get(data);
		if(overlayDrawableSize == null) {
			overlayDrawableSize = new int[2];
			overlayDrawableSize[0] = mOverlayDefaultDrawableWidth;
			overlayDrawableSize[1] = mOverlayDefaultDrawableHeight;
		} 
		if(flowPosition == AbsPopupView.FLOW_POSITION_TOP_CENTER) {
			offsetY = -(overlayDrawableSize[1] / 2);
		}
		else if(flowPosition == AbsPopupView.FLOW_POSITION_BOTTOM_CENTER) {
			offsetY = overlayDrawableSize[1] / 2;
		}
		//TODO 在以後會加上FLOW_POSITION_TOP_LEFT, FLOW_POSITION_TOP_RIGHT等等...
		lp.x = offsetX;
		lp.y = offsetY;
		MapLog.i(TAG, "Offset(" + lp.x + " , " + lp.y + ")");
		mMapView.updateViewLayout(popupView, lp);
		popupView.setVisibility(View.VISIBLE);
	}

	public void hidePopupViewForSingleMode() {
		if(mMode == PopupMode.SingleMode && mPopupViews.size() > 0) {
			mPopupViews.get(0).setVisibility(View.GONE);
		}
	}
	
	public void hideAllPopupView() {
		final int popupViewSize = mPopupViews.size();
		if(popupViewSize <= 0) {
			return ;
		}
		for(AbsPopupView popupView : mPopupViews) {
			popupView.setVisibility(View.GONE);
		}
	}
	
	public MapView getMapView() {
		return mMapView;
	}
	
	public static boolean hasInit() {
		return sHasInit;
	}
	
	public void updateData() {
		if(mPopupViews != null && mPopupViews.size() > 0 && mOverlayDatas != null) {
			if(mMode == PopupMode.SingleMode && mCurrentOverlayDataForSingleMode != null) {
				mPopupViews.get(0).setData(mCurrentOverlayDataForSingleMode);
			}
			else {
				showAllPopupViews();
			}
		}
	}
	
	public void destory() {
		if(mMapView != null) {
			mMapView.getOverlays().clear();
			mMapView = null;
		}
		if(mItemizedOverlay != null) {
			mItemizedOverlay.release();
			mItemizedOverlay = null;
		}
		if(mPopupViews != null) {
			for(AbsPopupView popupView : mPopupViews) {
				popupView.release();
			}
			mPopupViews.clear();
		}
		if(mOverlayDatas != null) {
			mOverlayDatas.clear();
			mOverlayDatas = null;
		}
		if(mOverlayDrawableSize != null) {
			mOverlayDrawableSize.clear();
			mOverlayDrawableSize = null;
		}
		mCurrentOverlayDataForSingleMode = null;
		mContext = null;
		mMode = null;
		mPopupViewClass = null;
		instance = null;
		sHasInit = false;
	}

}
